/*
 * SoapUI, Copyright (C) 2004-2017 SmartBear Software
 *
 * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent 
 * versions of the EUPL (the "Licence"); 
 * You may not use this work except in compliance with the Licence. 
 * You may obtain a copy of the Licence at: 
 * 
 * http://ec.europa.eu/idabc/eupl 
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the Licence is 
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
 * express or implied. See the Licence for the specific language governing permissions and limitations 
 * under the Licence. 
 */

package com.eviware.soapui.support.components;

import com.jgoodies.looks.HeaderStyle;
import com.jgoodies.looks.Options;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JInspectorPanelImpl extends JPanel implements PropertyChangeListener, JInspectorPanel {
    private float defaultDividerLocation = 0.65F;

    private final JSplitPane mainSplit;
    private JPanel inspectorPanel;
    private int lastDividerLocation = 0;
    private JXToolBar inspectToolbar;
    private List<Inspector> inspectors = new ArrayList<Inspector>();
    private Map<Inspector, JToggleButton> inspectorButtons = new HashMap<Inspector, JToggleButton>();
    public Inspector currentInspector;

    private final int orientation;

    public JInspectorPanelImpl(JComponent contentComponent) {
        this(contentComponent, SwingConstants.BOTTOM);
    }

    public JInspectorPanelImpl(JComponent contentComponent, int orientation) {
        super(new BorderLayout());
        this.orientation = orientation;

        inspectorPanel = new JPanel(new CardLayout());
        inspectorPanel.setVisible(false);

        mainSplit = new JSplitPane(
                orientation == SwingConstants.LEFT || orientation == SwingConstants.RIGHT ? JSplitPane.HORIZONTAL_SPLIT
                        : JSplitPane.VERTICAL_SPLIT);
        BasicSplitPaneUI basic = (BasicSplitPaneUI) mainSplit.getUI();
        basic.getDivider().setBorder(new LineBorder(Color.WHITE, 1) {
            @Override
            public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
                g.setColor(Color.LIGHT_GRAY);
                g.drawLine(c.getWidth() - 1, 0, c.getWidth() - 1, c.getHeight());
            }

        });
        mainSplit.setDividerSize(5);
        mainSplit.setBorder(null);
        mainSplit.setOneTouchExpandable(false);
        JXToolBar toolbar = createInspectButtons();
        if (orientation == SwingConstants.BOTTOM) {
            mainSplit.setTopComponent(contentComponent);
            mainSplit.setBottomComponent(inspectorPanel);
            mainSplit.setResizeWeight(0.8);
            toolbar.setBorder(BorderFactory.createEmptyBorder(1, 2, 3, 2));
            add(toolbar, BorderLayout.SOUTH);
        } else if (orientation == SwingConstants.LEFT) {
            mainSplit.setRightComponent(contentComponent);
            JPanel p = new JPanel(new BorderLayout());
            p.add(toolbar);
            p.setBorder(new LineBorder(Color.WHITE, 1) {
                @Override
                public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
                    g.setColor(Color.LIGHT_GRAY);
                    g.drawLine(c.getWidth() - 1, 0, c.getWidth() - 1, c.getHeight());
                }
            });
            toolbar.setBorder(BorderFactory.createEmptyBorder(2, 3, 0, 4));
            mainSplit.setLeftComponent(inspectorPanel);
            mainSplit.setResizeWeight(0.2);
            toolbar.setOrientation(JToolBar.VERTICAL);
            add(p, BorderLayout.WEST);
        } else if (orientation == SwingConstants.RIGHT) {
            mainSplit.setLeftComponent(contentComponent);

            JPanel p = new JPanel(new BorderLayout());
            p.add(toolbar);
            toolbar.setBorder(BorderFactory.createEmptyBorder(2, 1, 0, 3));
            mainSplit.setRightComponent(inspectorPanel);
            mainSplit.setResizeWeight(0.8);
            toolbar.setOrientation(JToolBar.VERTICAL);
            add(p, BorderLayout.EAST);
        }

        add(mainSplit, BorderLayout.CENTER);
    }

    private JXToolBar createInspectButtons() {
        inspectToolbar = new JXToolBar() {
            @Override
            public Dimension getMinimumSize() {
                return new Dimension(10, 10);
            }
        };

        inspectToolbar.setFloatable(false);
        inspectToolbar.setRollover(true);
        inspectToolbar.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.SINGLE);
        inspectToolbar.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0));

        if (orientation == SwingConstants.TOP || orientation == SwingConstants.BOTTOM) {
            inspectToolbar.addSpace(10);
        }
        inspectToolbar.setBackground(Color.WHITE);
        inspectToolbar.setOpaque(true);
        return inspectToolbar;
    }

    public float getDefaultDividerLocation() {
        return defaultDividerLocation;
    }

    public void setDefaultDividerLocation(float defaultDividerLocation) {
        this.defaultDividerLocation = defaultDividerLocation;
        setResetDividerLocation();
    }

    public <T extends Inspector> T addInspector(final T inspector) {
        if (inspectors.size() > 0) {
            inspectToolbar.addSpace(5);
        }

        inspectors.add(inspector);
        inspector.addPropertyChangeListener(JInspectorPanelImpl.this);
        inspectorPanel.add(inspector.getComponent(), inspector.getInspectorId());
        JToggleButton button = new JToggleButton(new SelectInspectorAction(inspector));
        button.setName(inspector.getInspectorId());

        inspectorButtons.put(inspector, button);
        if (orientation == SwingConstants.LEFT) {
            String text = button.getText();
            button.setText(null);
            button.setPreferredSize(new Dimension(17, 10));
            button.setIcon(new VTextIcon(inspectToolbar, text, VTextIcon.ROTATE_LEFT));
            inspectToolbar.add(button);
        } else if (orientation == SwingConstants.RIGHT) {
            String text = button.getText();
            button.setText(null);
            button.setPreferredSize(new Dimension(17, 10));
            button.setIcon(new VTextIcon(inspectToolbar, text, VTextIcon.ROTATE_RIGHT));
            inspectToolbar.add(button);
        } else {
            inspectToolbar.add(button);
        }

        button.setMinimumSize(new Dimension(10, 10));

        inspectToolbar.invalidate();
        repaint();

        return inspector;
    }

    public Inspector getInspector(String inspectorId) {
        for (Inspector inspector : inspectors) {
            if (inspector.getInspectorId().equals(inspectorId)) {
                return inspector;
            }
        }

        return null;
    }

    public Inspector getInspectorByTitle(String title) {
        for (Inspector inspector : inspectors) {
            if (inspector.getTitle().equals(title)) {
                return inspector;
            }
        }

        return null;
    }

    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(Inspector.ENABLED_PROPERTY)) {
            JToggleButton toggleButton = inspectorButtons.get(evt.getSource());
            if (toggleButton != null) {
                toggleButton.setEnabled((Boolean) evt.getNewValue());
            }
        }
    }

    public JComponent getComponent() {
        return this;
    }

    public class SelectInspectorAction extends AbstractAction implements PropertyChangeListener {
        private final Inspector inspector;

        public SelectInspectorAction(Inspector inspector) {
            super(inspector.getTitle());
            this.inspector = inspector;

            putValue(AbstractAction.SHORT_DESCRIPTION, inspector.getDescription());
            putValue(AbstractAction.SMALL_ICON, inspector.getIcon());
            setEnabled(inspector.isEnabled());

            inspector.addPropertyChangeListener(this);
        }

        public void actionPerformed(ActionEvent arg0) {
            JToggleButton button = inspectorButtons.get(inspector);
            if (!button.isSelected()) {
                deactivate();
                // currentInspector = null;
                // button.setBackground( inspectToolbar.getBackground() );
                // lastDividerLocation = mainSplit.getDividerLocation();
                // inspectorPanel.setVisible( false );
            } else {
                activate(inspector);
            }
        }

        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(Inspector.TITLE_PROPERTY)) {
                putValue(AbstractAction.NAME, evt.getNewValue());
            } else if (evt.getPropertyName().equals(Inspector.ICON_PROPERTY)) {
                putValue(AbstractAction.SMALL_ICON, evt.getNewValue());
            } else if (evt.getPropertyName().equals(Inspector.DESCRIPTION_PROPERTY)) {
                putValue(AbstractAction.SHORT_DESCRIPTION, evt.getNewValue());
            } else if (evt.getPropertyName().equals(Inspector.ENABLED_PROPERTY)) {
                boolean enable = ((Boolean) evt.getNewValue()).booleanValue();
                setEnabled(enable);

                if (!enable && currentInspector == inspector) {
                    inspectorButtons.get(currentInspector).setSelected(false);
                }
            }
        }
    }

    public void release() {
        for (Inspector inspector : inspectors) {
            inspector.removePropertyChangeListener(this);
            inspector.release();
        }

        inspectors.clear();
        inspectorPanel.removeAll();
        mainSplit.removeAll();
    }

    public List<Inspector> getInspectors() {
        return inspectors;
    }

    public Inspector getCurrentInspector() {
        return currentInspector;
    }

    public void setInspectorsVisible(boolean b) {
        inspectorPanel.setVisible(b);
    }

    public void setInspectorVisible(Inspector inspector, boolean b) {
        if (inspectorButtons.containsKey(inspector)) {
            if (!b && inspector == currentInspector) {
                activate(null);
            }

            inspectorButtons.get(inspector).setVisible(b);
        }
    }

    public void setToolbarVisible(boolean b) {
        inspectToolbar.setVisible(b);
    }

    public double getResizeWeight() {
        return mainSplit.getResizeWeight();
    }

    public void setResizeWeight(double value) {
        mainSplit.setResizeWeight(value);
    }

    public int getDividerLocation() {
        return mainSplit.getDividerLocation();
    }

    public void setResetDividerLocation() {
        mainSplit.setDividerLocation(defaultDividerLocation);
    }

    public void setDividerLocation(int dividerLocation) {
        mainSplit.setDividerLocation(dividerLocation);
    }

    public void setCurrentInspector(String string) {
        for (Inspector inspector : inspectors) {
            if (inspector.getTitle().equals(string)) {
                activate(inspector);
                break;
            }
        }
    }

    public void deactivate() {
        activate(null);
    }

    public void activate(Inspector inspector) {
        if (inspector == currentInspector) {
            return;
        }

        if (currentInspector != null) {
            inspectorButtons.get(currentInspector).setSelected(false);
            currentInspector.deactivate();
        }

        if (inspector == null) {
            currentInspector = null;
            inspectorPanel.setVisible(false);
        } else {
            JToggleButton button = inspectorButtons.get(inspector);
            currentInspector = inspector;

            button.setSelected(true);
            button.setBackground(Color.WHITE);

            if (!inspectorPanel.isVisible()) {
                inspectorPanel.setVisible(true);
                if (lastDividerLocation == 0) {
                    mainSplit.setDividerLocation(defaultDividerLocation);
                } else {
                    mainSplit.setDividerLocation(lastDividerLocation);
                }
            }

            CardLayout cards = (CardLayout) inspectorPanel.getLayout();
            cards.show(inspectorPanel, inspector.getInspectorId());

            currentInspector.activate();
        }
    }

    public void setContentComponent(JComponent content) {
        mainSplit.setTopComponent(content);
    }

    public void removeInspector(Inspector inspector) {
        if (currentInspector == inspector) {
            deactivate();
        }

        inspector.release();
        inspectors.remove(inspector);
        JToggleButton toggleButton = inspectorButtons.get(inspector);

        int ix = inspectToolbar.getComponentIndex(toggleButton);
        if (ix > 1) {
            inspectToolbar.remove(ix - 1);
        }

        inspectToolbar.remove(toggleButton);
        inspectorPanel.remove(inspector.getComponent());
        inspectToolbar.repaint();
        inspectorButtons.remove(inspector);
    }
}
